package br.ufrn.engcomp.domain;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import br.ufrn.engcomp.arq.PersistDB;

/**
 * Representa um controlador PID (Proporcional-Integral-Derivativo)
 * 
 * @author Victor Carvalho Galvao de Freitas
 * 
 */
@Entity
@Table(name = "pid_controller")
public class PIDController implements PersistDB, Serializable {

    /** Constantes que servem para indicar o tipo de controlador desejado **/
    public static final int P = 0;
    public static final int PI = 1;
    public static final int PD = 2;
    public static final int PID = 3;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pid_controller_seq")
    @SequenceGenerator(name = "pid_controller_seq", sequenceName = "id_pid_controller", allocationSize = 0)
    private int id;

    private Integer type;

    private Double kp;

    private Double ki;

    private Double kd;

    private boolean antiWindup;

    private boolean flatSaturacao;

    @Transient
    private double ts;

    @Transient
    private double controlSignal;

    @Transient
    private double iAnterior;

    @Transient
    private double erroAnterior;

    @Transient
    private double erroAtual;

    @Transient
    private double saidaAnterior;

    @Transient
    private double saidaAtual;

    public PIDController() {
	ts = ((double) TanquesAcoplados.tS) / 1000;
	erroAtual = 0;
	erroAnterior = 0;
	iAnterior = 0;
	antiWindup = false;
	flatSaturacao = false;
    }

    public void clear() {
	erroAnterior = 0;
	iAnterior = 0;
	saidaAnterior = 0;
    }

    public double getSinalControlePID(double erro) {
	controlSignal = kp * erro + ki*iAnterior + ki * ts * erroAtual + kd * (erro - erroAnterior) / ts;
	erroAnterior = erro;
	if (!flatSaturacao)
	    iAnterior += ki * (0.1 * erro);

	return controlSignal;
    }

    public double getSinalControlePI_D(double erro, double saidaAtual) {
	controlSignal = kp * erro + ki*iAnterior + ki * ts * erroAtual + kd * (saidaAtual - saidaAnterior) / ts;
	saidaAnterior = saidaAtual;
	if (!flatSaturacao){
	    iAnterior += ki * (0.1 * erro);
	} else {
	    System.out.println("saturado no controlador");
	}
	System.out.println("PI-D");
	System.out.println("erro: " + erro);
	System.out.println("iAnterior: " + iAnterior);
	return controlSignal;
    }

    public Integer getType() {
	return type;
    }

    public void setType(Integer type) {
	this.type = type;
    }

    public Double getKp() {
	return kp;
    }

    public void setKp(Double kp) {
	this.kp = kp;
    }

    public Double getKi() {
	return ki;
    }

    public void setKi(Double ki) {
	this.ki = ki;
    }

    public Double getKd() {
	return kd;
    }

    public void setKd(Double kd) {
	this.kd = kd;
    }

    public int getId() {
	return id;
    }

    public void setId(int id) {
	this.id = id;
    }

    public boolean isAntiWindup() {
	return antiWindup;
    }

    public void setAntiWindup(boolean antiWindup) {
	this.antiWindup = antiWindup;
    }

    public boolean isFlatSaturacao() {
	return flatSaturacao;
    }

    public void setFlatSaturacao(boolean flatSaturacao) {
	this.flatSaturacao = flatSaturacao;
    }

}
